home *** CD-ROM | disk | FTP | other *** search
-
- /*
- * (a) (C) 1990 by Adobe Systems Incorporated. All rights reserved.
- *
- * (b) If this Sample Code is distributed as part of the Display PostScript
- * System Software Development Kit from Adobe Systems Incorporated,
- * then this copy is designated as Development Software and its use is
- * subject to the terms of the License Agreement attached to such Kit.
- *
- * (c) If this Sample Code is distributed independently, then the following
- * terms apply:
- *
- * (d) This file may be freely copied and redistributed as long as:
- * 1) Parts (a), (d), (e) and (f) continue to be included in the file,
- * 2) If the file has been modified in any way, a notice of such
- * modification is conspicuously indicated.
- *
- * (e) PostScript, Display PostScript, and Adobe are registered trademarks of
- * Adobe Systems Incorporated.
- *
- * (f) THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO
- * CHANGE WITHOUT NOTICE, AND SHOULD NOT BE CONSTRUED
- * AS A COMMITMENT BY ADOBE SYSTEMS INCORPORATED.
- * ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY
- * OR LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO
- * WARRANTY OF ANY KIND (EXPRESS, IMPLIED OR STATUTORY)
- * WITH RESPECT TO THIS INFORMATION, AND EXPRESSLY
- * DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT
- * OF THIRD PARTY RIGHTS.
- */
-
- /*
- * rotateprocs.c
- *
- * This file contains procedure that perform operations
- * on rotated rectangles and points.
- *
- * Note: the angle in the procedures below should be expressed
- * in radians and not degrees.
- *
- * Version: 2.0
- * Author: Ken Fromm
- * History:
- * 03-07-91 Added this comment.
- */
-
- #import <appkit/graphics.h>
- #import <appkit/nextstd.h>
- #import <math.h>
-
- /*
- * Takes the point passed in, rotates it around the point
- * at the angle given and returns the new point.
- * The new point replaces the old one and its address
- * is returned as the return value.
- */
- NXPoint *RotatePoint(NXPoint *aPoint, NXPoint *cPoint, float angle)
- {
- float d, dx, dy;
-
- float ang;
-
- if (aPoint && cPoint && angle != 0)
- {
- dx = aPoint->x - cPoint->x;
- dy = aPoint->y - cPoint->y;
-
- *aPoint = *cPoint;
- d = sqrt(dx * dx + dy * dy);
- if (d != 0.0)
- {
- ang = angle + (float) atan2(dy, dx);
- aPoint->x += d * cos(ang);
- aPoint->y += d * sin(ang);
- }
- }
-
- return aPoint;
- }
-
- /*
- * Checks whether the point passed in lies in the rectangle
- * rotated about its lower left vertice at the angle provided.
- * Returns either YES or NO. Assumes an unflipped
- * coordinate system.
- */
- BOOL MouseInRotatedRect(NXPoint *aPoint, NXRect *aRect, float angle)
- {
- NXPoint pt;
-
- if (aRect && aPoint)
- {
- pt = *aPoint;
- RotatePoint(&pt, &aRect->origin, -angle);
-
- return NXMouseInRect(&pt, aRect, NO);
- }
- else
- return NO;
- }
-
- /*
- * This procedure takes the unrotated rectangle, bRect,
- * rotates it around the point, cPoint, at the angle, angle,
- * and places the new bounding box that encloses the
- * rotated rectangle in the rectangle aRect. The address
- * of the new rectangle is returned as the return value.
- *
- * Figuring the new width and height is relatively
- * straight-forward. Just take the sin and cos of the
- * old width and height.
- *
- * Figuring the new origin is a bit different. The vertices
- * for the lower x and lower y coordinates are chosen
- * based on the angle to rotate. Their positions in the rotated
- * spaced are calculated and subtracted from the center point.
- */
- NXRect *RotateRectBounds(NXRect *aRect, const NXRect *bRect, NXPoint *cPoint, float angle)
- {
- float dx, dy, dxx, dxy, dyx, dyy;
-
- double cosa, sina;
-
- if (aRect && bRect && cPoint)
- {
- if (angle != 0)
- {
- cosa = cos(angle);
- sina = sin(angle);
-
- dyx = dxx = bRect->origin.x - cPoint->x;
- dyy = dxy = bRect->origin.y - cPoint->y;
-
- if (cosa > 0)
- {
- if (sina > 0)
- dxy += bRect->size.height;
- else
- dyx += bRect->size.width;
- }
- else
- {
- if (sina > 0)
- {
- dxx += bRect->size.width;
- dyy = dxy = dxy + bRect->size.height;
- }
- else
- {
- dyx = dxx = dxx + bRect->size.width;
- dyy += bRect->size.height;
- }
- }
-
- aRect->origin = *cPoint;
-
- dx = sqrt(dxx * dxx + dxy * dxy);
- if (dx != 0.0)
- aRect->origin.x += (float) dx * cos(angle + atan2(dxy, dxx));
- dy = sqrt(dyx * dyx + dyy * dyy);
- if (dy != 0.0)
- aRect->origin.y += (float) dy * sin(angle + atan2(dyy, dyx));
-
- aRect->size.width = (float) (ABS(bRect->size.width * cosa) +
- ABS(bRect->size.height * sina));
- aRect->size.height = (float) (ABS(bRect->size.width * cos(M_PI_2 - angle)) +
- ABS(bRect->size.height * sin(M_PI_2 - angle)));
- }
- else
- *aRect = *bRect;
- }
-
- return aRect;
- }
-
- /*
- * This procedure calculates the minimum hypotense
- * for a width and a height. The width and height are
- * meant to be from different triangles sharing the same
- * angles.
- */
- static double DistanceToEdge(float x, float y, float angle)
- {
- float dx, dy;
-
- double cosa, sina;
-
- cosa = cos(angle);
- if (cosa != 0.0)
- dx = ABS(x / cosa);
- else
- dx = y;
-
- sina = sin(angle);
- if (sina != 0.0)
- dy = ABS(y / sina);
- else
- dy = x;
-
- return MIN(dx, dy);
- }
-
- /*
- * This procedure takes two rectangles and an angle.
- * It checks if the second rectangle rotated about its origin
- * at the given angle intersects the first rectangle. The
- * first rectangle is unrotated.
- *
- * It checks for intersection by comparing the distance between
- * the centers to the sum of the distance from the centers to the
- * edges. If the distance between the centers is less than the
- * sum of the distance to the edges, the rectangles intersect.
- */
- BOOL IntersectsRotatedRect(NXRect *aRect, NXRect *bRect, float angle)
- {
- BOOL intersect = NO;
-
- float d, dx, dy, da, db;
-
- float ang;
-
- NXPoint bCenter;
-
- if (aRect && bRect)
- {
- if (angle != 0.0)
- {
- bCenter.x = bRect->origin.x + bRect->size.width/2;
- bCenter.y = bRect->origin.y + bRect->size.height/2;
- RotatePoint(&bCenter, &bRect->origin, angle);
-
- dx = bCenter.x - (aRect->origin.x + aRect->size.width/2);
- dy = bCenter.y - (aRect->origin.y + aRect->size.height/2);
- d = sqrt(dx*dx + dy*dy);
- if (d)
- {
- ang = (float) atan2(dy, dx);
- da = DistanceToEdge(aRect->size.width/2, aRect->size.height/2, ang);
- ang = ang + M_PI_2 - angle;
- db = DistanceToEdge(bRect->size.width/2, bRect->size.height/2, ang);
-
- intersect = (d <= da + db);
- }
- else
- intersect = YES;
- }
- else
- intersect = NXIntersectsRect(aRect, bRect);
- }
-
- return intersect;
- }
-
- /*
- * This procedure takes two points and constrains the first
- * point to the nearest 15% interval.
- */
- void ConstrainPointToAngle(NXPoint *aPoint, NXPoint *cPoint, float angle)
- {
- float d, dx, dy, a;
-
- dx = aPoint->x - cPoint->x;
- dy = aPoint->y - cPoint->y;
- d = sqrt(dx*dx + dy*dy);
-
- if (d != 0.0)
- {
- a = rint(atan2(dy, dx) / angle) * angle;
- aPoint->x = (float) cPoint->x + d * cos(a);
- aPoint->y = (float) cPoint->y + d * sin(a);
- }
- }
-
-